package cn.iocoder.yudao.framework.operate.core.media.impl.ocean;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.net.URLEncodeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.operate.core.enums.GoodsFrameworkErrorCodeConstants;
import cn.iocoder.yudao.framework.operate.core.media.MediaCodeMapping;
import cn.iocoder.yudao.framework.operate.core.media.dto.account.AccountReqDTO;
import cn.iocoder.yudao.framework.operate.core.media.dto.account.AccountRespDTO;
import cn.iocoder.yudao.framework.operate.core.media.dto.token.RefreshTokenReqDO;
import cn.iocoder.yudao.framework.operate.core.media.dto.token.TokenReqDO;
import cn.iocoder.yudao.framework.operate.core.media.dto.token.TokenRespDO;
import cn.iocoder.yudao.framework.operate.core.media.impl.AbstractMediaClient;
import cn.iocoder.yudao.framework.operate.core.property.MediaProperties;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

@Slf4j
public class OceanClient extends AbstractMediaClient {

    // 京东api请求地址
    protected final static String ENDPOINT = "https://open.douyin.com";
    protected final static String API = "/open_api";
    // 请求获取token
    protected final static String ACCESS_TOKEN_M = "/oauth/access_token/";
    // 刷新token
    protected final static String REFRESH_TOKEN_M = "/oauth/refresh_token/";
    // 刷新 refresh_token
    protected final static String RE_REFRESH_TOKEN_M = "/oauth/renew_refresh_token/";
    /// 获取授权信息(用户公开信息)
    protected final static String ADVERTISER_GET_M = "/oauth/userinfo/";
    // 线索上报API
    protected final static String ADVERTISER_TRACK = "/track/activate/";

    protected final static String GET_AUTH_API = "/platform/oauth/connect/";

    private final String scope = "user_info,video.create.bind";


//    private volatile JdClient client;

    private final static String VERSION = "1.0";

    private final static Integer OK_CODE = 200;

    public OceanClient(MediaProperties properties, MediaCodeMapping codeMapping) {
        super(properties, codeMapping);
    }

    public OceanClient(MediaProperties properties) {
        super(properties, new OceanCodeMapping());
        Assert.notEmpty(properties.getAppKey(), "appKey 不能为空");
        Assert.notEmpty(properties.getAppSecret(), "appSecret 不能为空");
        Assert.notEmpty(properties.getAccessNotifyUrl(), "授权回调地址不能为空");
    }


    @Override
    protected void doInit() {
//        client = new DefaultJdClient(ENDPOINT, "", properties.getAppKey(), properties.getAppSecret());
    }

    /**
     * 创建 access_token
     */
    @Override
    public TokenRespDO createAccessToken(TokenReqDO tokenReqDO) {
        Map<String, Object> data = new HashMap<String, Object>() {
            {
                put("client_key", properties.getAppKey());
                put("client_secret", properties.getAppSecret());
                put("grant_type", "authorization_code");
                put("code", tokenReqDO.getAuthCode());
            }
        };
        String body = postRequest(StrUtil.concat(true, ENDPOINT, ACCESS_TOKEN_M), data);
        return convertTokenRespDO(body);
    }

    /**
     * 刷新 access_token
     * @return TokenRespDO tokenRespDO
     */
    @Override
    public TokenRespDO refreshAccessToken(RefreshTokenReqDO tokenReqDO) {
        Map<String, Object> data = new HashMap<String, Object>() {
            {
                put("client_key", properties.getAppKey());
                put("grant_type", "refresh_token");
                put("refresh_token", tokenReqDO.getRefreshToken());
            }
        };
        String body = postRequest(StrUtil.concat(true, ENDPOINT, REFRESH_TOKEN_M), data);
        return convertTokenRespDO(body);
    }

    @Override
    public TokenRespDO renewRefreshAccessToken(RefreshTokenReqDO tokenReqDO) {
        Map<String, Object> data = new HashMap<String, Object>() {
            {
                put("client_key", properties.getAppKey());
                put("refresh_token", tokenReqDO.getRefreshToken());
            }
        };
        String body = postRequest(StrUtil.concat(true, ENDPOINT, REFRESH_TOKEN_M), data);
        return convertTokenRespDO(body);
    }

    @Override
    public AccountRespDTO getAccountInfo(AccountReqDTO reqDTO) {
        Map<String, Object> data = new HashMap<String, Object>() {
            {
                put("open_id", reqDTO.getOpenId());
                put("access_token", reqDTO.getAccessToken());
            }
        };
        String body = postRequest(StrUtil.concat(true, ENDPOINT, ADVERTISER_GET_M), ContentType.FORM_URLENCODED.getValue(), data);
        return convertAccountRespDO(body);
    }

    @Override
    public boolean doUpload(String landingUrl) {
        Map<String, Object> toParam = new HashMap<>();
        toParam.put("event_type", 2);
        toParam.put("link", URLEncodeUtil.encode(landingUrl));
        String res = HttpUtil.get(ENDPOINT  + ADVERTISER_TRACK, toParam);
        return true;
    }

    @Override
    public String getAuthUrl(String state) {
        Map<String, Object> data = new HashMap<String, Object>() {
            {
                put("client_key", properties.getAppKey());
                put("response_type", "code");
                put("scope", scope);
                put("redirect_uri", properties.getAccessNotifyUrl());
                put("state", state);
            }
        };
        return StrUtil.concat(true, ENDPOINT, GET_AUTH_API) + "?" + HttpUtil.toParams(data);
    }

    /**
     * 将请求结果转化成token信息
     * @param result
     * @since 2024-01-17
     * @author PetePower
     * @return
     */
    public TokenRespDO convertTokenRespDO(String result) {
        JSONObject json = JSONUtil.parseObj(result);
        JSONObject respData = json.getJSONObject("data");
        if (!ObjectUtil.equals(0, respData.getInt("error_code"))) {
            throw new ServiceException(GoodsFrameworkErrorCodeConstants.HTTP_ERROR);
        }
        TokenRespDO tokenRespDO = new TokenRespDO();
        tokenRespDO.setAccessToken(respData.getStr("access_token"));
        tokenRespDO.setRefreshToken(respData.getStr("refresh_token"));
        tokenRespDO.setExpireIn(respData.getInt("expires_in"));
        tokenRespDO.setRefreshExpireIn(respData.getInt("refresh_expires_in"));
        tokenRespDO.setScope(respData.getStr("scope"));
        tokenRespDO.setOpenId(respData.getStr("open_id"));
        return tokenRespDO;
    }

    /**
     * 将请求结果转换成用户账户信息
     * @param result
     * @since 2024-01-17
     * @author PetePower
     * @return
     */
    public AccountRespDTO convertAccountRespDO(String result) {
        JSONObject json = JSONUtil.parseObj(result);
        JSONObject respData = json.getJSONObject("data");
        if (!ObjectUtil.equals(0, respData.getInt("error_code"))) {
            throw new ServiceException(GoodsFrameworkErrorCodeConstants.HTTP_ERROR);
        }
        AccountRespDTO accountRespDTO = new AccountRespDTO();
        accountRespDTO.setNickname(respData.getStr("nickname"));
        accountRespDTO.setAvatar(respData.getStr("avatar"));
        accountRespDTO.setUnionId(respData.getStr("union_id"));
        // 这个用户身份暂时先不用了， 没什么用处
        accountRespDTO.setAccountRole(respData.getStr("e_account_role"));
        return accountRespDTO;
    }

    public String postRequest(String url, Map<String,Object> data) {
        return postRequest(url, ContentType.JSON.getValue(), data);
    }

    public String postRequest(String url, String contentType, Map<String,Object> data) {
        HttpResponse res = HttpUtil.createPost(url)
                .header(Header.CONTENT_TYPE, contentType)
                .body(JSONUtil.toJsonStr(data))
                .execute();
        if (!ObjectUtil.equals(200, res.getStatus())) {
            throw new ServiceException(GoodsFrameworkErrorCodeConstants.HTTP_ERROR);
        }
        res.close();
        return res.body();
    }

}
